using System;
using System.Collections.Generic;
using System.Text;

namespace RapidHDL
{
    public class RemoteSynth
    {
        Structure oStructure;
        Settings oSettings;

        public RemoteSynth(Structure poStructure)
        {
            oStructure = poStructure;
            oSettings = oStructure.RapidHardware.Settings;
        }

        public string XilinxRemoteBuild()
        {
            if (CheckXilinxSynthesisBusy())
                return "Remote server is busy";

            // need to update RHDLSynthONly to unpack this
            // for now, manually copy these files up to the build server just once
            /*if (!UploadFileDirectory(oSettings.InterfaceSourcePath, "*", oSettings.BuildServerPath))
                return "Error uploading files to remote server";*/

            if (!UploadFileDirectory(oSettings.OutputPath, "v", oSettings.BuildServerPath))
                return "Error uploading files to remote server";

            if (!PostFile(TextFile.BuildFileName(oSettings.OutputPath, "xst.prj"), "xst.prj",oSettings.BuildServerPath))
                return "Error uploading xst.prj";


            string sResult = StartXilinxSynthesis();
            if (sResult != "ok")
                return sResult;

            while (CheckXilinxSynthesisBusy())
            {
                System.Threading.Thread.Sleep(1000);
                System.Windows.Forms.Application.DoEvents();
            }

            GetRemoteFiles();

            string sServerResult = ReadHandshake();
            CompleteXilinxSynthesis();
            if (sServerResult == "success")
                return "";

            return sServerResult;
        }

        public bool UploadFileDirectory(string psFolderPath, string psFilterExtention, string psURL)
        {
            Synth oRemote = new Synth(psURL);

            if (!TextFile.FolderExists(psFolderPath))
                return false;

            string sFileName = psFilterExtention + ".o.tar.gz";
            if (psFilterExtention == "*")
                sFileName = "all.o.tar.gz";

            TextFile.WipeDirectory(psFolderPath, "*.tar");
            TextFile.WipeDirectory(psFolderPath, "*.gz");

            string sCommand = "tar";
            //string sParam = " -cvf " + TextFile.BuildFileName(psFolderPath, psFilterExtention + ".o.tar") + " " + TextFile.BuildFileName(psFolderPath,"*." + psFilterExtention);
            string sParam = " -cvf " + psFilterExtention + ".o.tar" + " " + "*." + psFilterExtention;
            if (psFilterExtention == "*")
                sParam = " -cvf " + "all.o.tar" + " " + "*." + psFilterExtention;
            ShellControl.KillAllProcesses("tar");
            ShellControl.StartExe(sCommand, psFolderPath, sParam);
            while (ShellControl.GetProcessCount(sCommand) > 0)
            {
                System.Threading.Thread.Sleep(2000);
            }

            sCommand = "gzip";
            //sParam = " " + TextFile.BuildFileName(psFolderPath,psFilterExtention + ".o.tar");
            sParam = " " + psFilterExtention + ".o.tar";
            if (psFilterExtention == "*")
                sParam = " all.o.tar";            
            ShellControl.KillAllProcesses("gzip");
            ShellControl.StartExe(sCommand, psFolderPath, sParam);
            while (ShellControl.GetProcessCount(sCommand) > 0)
            {
                System.Threading.Thread.Sleep(2000);
            }


            //System.Console.WriteLine(sFileName);
            if (!PostFile(TextFile.BuildFileName(psFolderPath, sFileName), sFileName, oSettings.BuildServerPath))
                return false;

            /*string[] saFiles = System.IO.Directory.GetFiles(psFolderPath);
            foreach (string sFile in saFiles)
            {
                string sFileName = Utility.StringTakeRightFromEnd(sFile, '\\');
                bool bUpload = false;
                if (psFilterExtention != "*")
                {
                    if (TextFile.GetExtention(sFileName) == psFilterExtention)
                        bUpload = true;
                }
                else
                    bUpload = true;

                if (bUpload)
                {
                    //System.Console.WriteLine(sFileName);
                    if (!PostFile(TextFile.BuildFileName(psFolderPath, sFileName), sFileName,oSettings.BuildServerPath))
                        return false;
                }
            }*/
            return true;
        }

        public void GetRemoteFiles()
        {
            string[] logNames = XilinxTools.LogFileNames(oSettings.TopComponentName);
            foreach (string sLogFile in logNames)
            {
                string sFilePath = TextFile.BuildFileName(oSettings.OutputPath,sLogFile);
                GetFile(sFilePath, sLogFile,oSettings.BuildServerPath);
            }
            string sBitFile = oSettings.TopComponentName + ".bit";
            string sPath = TextFile.BuildFileName(oSettings.OutputPath, sBitFile);
            GetFile(sPath, sBitFile,oSettings.BuildServerPath);
        }


        public bool PostFile(string psFullFilePath, string psShortFileName, string psURL)
        {
            Synth oRemote = new Synth(psURL);

            System.IO.BinaryReader oBinaryReader = new System.IO.BinaryReader(System.IO.File.Open(psFullFilePath, System.IO.FileMode.Open, System.IO.FileAccess.Read));
            oRemote.Credentials = System.Net.CredentialCache.DefaultCredentials;
            oBinaryReader.BaseStream.Position = 0;
            byte[] buffer = oBinaryReader.ReadBytes(Convert.ToInt32(oBinaryReader.BaseStream.Length));
            oBinaryReader.Close();
            oRemote.PutFile(buffer, psShortFileName);
            /*}
            catch
            {
                return false;
            }*/
            return true;
        }

        public bool GetFile(string psFullFilePath, string psShortFileName, string psURL)
        {
            Synth oRemote = new Synth(psURL);
            oRemote.Credentials = System.Net.CredentialCache.DefaultCredentials;

            try
            {
                //string filename = "c:\\temp\\" + Guid.NewGuid().ToString() + ".tmp";
                byte[] buffer = oRemote.GetFile(psShortFileName);
                System.IO.BinaryWriter oBinaryWriter = new System.IO.BinaryWriter(System.IO.File.Open(psFullFilePath, System.IO.FileMode.Create, System.IO.FileAccess.Write));
                oBinaryWriter.Write(buffer, 0, Convert.ToInt32(buffer.Length));
                oBinaryWriter.Close();
            }
            catch
            {
                return false;
            }
            return true;
        }

        /*public string SynthXilinx()
        {
            Synth oRemote = new Synth();
            RapidHDL.Settings oSettings = new RapidHDL.Settings();

            oRemote.Credentials = System.Net.CredentialCache.DefaultCredentials;
            string sResult = oRemote.SynthXilinx(oSettings.TopComponentName, oSettings.XilinxChip, oSettings.OptimizeSpeed,psUCF);
            if (sResult == "")
                sResult = "OK!";
            return sResult;
        }*/

        public string ReadHandshake()
        {
            if (!Utility.IsUnix())
            {
                if (!GetFile("c:\\temp\\handshake.txt", "handshake.txt",oSettings.BuildServerPath))
                    return "ERROR";
            }
            return ReadStatusFile("c:\\temp\\handshake.txt");
        }

        public bool WriteHandshake(string psStatus)
        {
            WriteStatusFile("c:\\temp\\handshake.txt", psStatus);

            if (!Utility.IsUnix())
            {
                if (!PostFile("c:\\temp\\handshake.txt", "handshake.txt",oSettings.BuildServerPath))
                    return false;
            }
            return true;
        }

        public string WriteStatusFile(string psFileName, string psStatus)
        {
            try
            {
                System.IO.StreamWriter oFile = RapidHDL.TextFile.OpenFileReWrite(psFileName);
                oFile.Write(psStatus);
                oFile.Close();
                return "";
            }
            catch
            {
                return "Unable to open status file : " + psFileName.ToString();
            }
        }

        public string ReadStatusFile(string psFileName)
        {
            try
            {
                System.IO.StreamReader oFile = RapidHDL.TextFile.OpenFileRead(psFileName);
                string sResult = oFile.ReadToEnd();
                oFile.Close();
                return sResult;
            }
            catch
            {
                return "Unable to read status file : " + psFileName.ToString();
            }
        }

        public string StartXilinxSynthesis()
        {
            string sHandshake = ReadHandshake();
            if (sHandshake == "busy")
                return sHandshake;

            if (sHandshake == "ERROR")
                return "SERVER CONNECTION ERROR";

            if (sHandshake != "ready")
            {
                if (!WriteHandshake("done"))
                    return "CANNOT WRITE TO SERVER";
                System.Threading.Thread.Sleep(5000);
                sHandshake = ReadHandshake();
            }

            if (sHandshake != "ready")
            {
                return "Server Handshake Error - " + sHandshake;
            }

            WriteHandshake("go");
            System.Threading.Thread.Sleep(4000);

            return "ok";
        }

        public bool CheckXilinxSynthesisBusy()
        {
            string sHandshake = ReadHandshake();
            if (sHandshake == "working")
                return true;
            else
                return false;
        }

        public string CompleteXilinxSynthesis()
        {
            string sHandshake = ReadHandshake();
            WriteHandshake("done");
            return sHandshake;
        }

    }
}
